#define	_ARH_KONTEKST_C_
#include "kontekst.h"
#include "spremnik.h"

void *arh_dohvati_vrh_stoga_dretve(kontekst_dretve_t *kontekst)
{
	return (void *) (kontekst->esp);
}

// stog dretve mora biti spreman za povratak iz prekida
void arh_izgradi_prekidni_stog (void *stog, void *jstog, void *pb)
{
	kontekst_dretve_t *pstog = jstog;

	pstog->eflags = POC_REG_STANJA; /* registar stanja */

	pstog->cs = GDT_OPISNIK(SEG_INSTR, GDT, RAZINA_KORISNIKA);

	pstog->ds = GDT_OPISNIK(SEG_PODACI, GDT, RAZINA_KORISNIKA);
	pstog->es = GDT_OPISNIK(SEG_PODACI, GDT, RAZINA_KORISNIKA);
	pstog->fs = GDT_OPISNIK(SEG_PODACI, GDT, RAZINA_KORISNIKA);
	pstog->gs = GDT_OPISNIK(SEG_PODACI, GDT, RAZINA_KORISNIKA);

	pstog->ss = GDT_OPISNIK(SEG_PODACI, GDT, RAZINA_KORISNIKA);
	pstog->esp = (uint32) arh_jup(stog);


	pstog->eip = (uint32) pb;	/* programsko br. */

	pstog->kod_greske = 0;	/* zamjenski kod greske */
	
	/* sadrzaj opcih registara je nebitan */
}

#include <jezgra/ispis.h>
void *arh_dodaj_obradu (void *_kontekst, void *obrada, uint32 vp_na_stogu, ...)
//"vp_na_stogu" = velicina parametara (...) na stogu u 'uint32' jedinicama
//umetnuta funkcija mora izgledati: um_fun(void *stari_vrh_stoga, ...)
//ali ne koristiti 'stari_vrh_stoga' jer to nije adresa u procesu (nije rel.)
{
	kontekst_dretve_t *kontekst = _kontekst, *kopija;
	uint32 *param = &vp_na_stogu;
	uint32 *stog;
	void *stog_prije = arh_puj((void *) kontekst->esp);
	int i;
	
	//j_ispisi("stog prije: %x\n", stog_prije);
	//kopiraj kontekst na stog dretve
	kopija = stog_prije;
	kopija--; //mjesto za kopiju konteksta
	*kopija = *kontekst; //kopira kontekst na stog dretve

	//umetni umetnutu funkciju u programsko brojilo
	kontekst->eip = (uint32) obrada; 

	stog = (uint32 *) kopija;
	stog -= vp_na_stogu + 2;
	//+1 za povratnu adresu (nula);
	//+1 za adresu vrha stoga prije = prvi parametar umetnute funkcije

	kontekst->esp = (uint32) arh_jup(stog);

	*stog = 0;//"povratna adresa" na vrhu stoga

	*(++stog) = (uint32) stog_prije; //prvi parametar funkcije

	//stavi (prekopiraj) parametre na stog dretve
	for (i = 0; i < vp_na_stogu; i++) {
		*(++stog) = *(++param);
	}

	return stog_prije;
}

void arh_makni_obradu (void *_kontekst, void *vrh_stoga)
{
	kontekst_dretve_t *kontekst = _kontekst, *kopija;
	
	kopija = vrh_stoga;
	kopija--; //stari kontekst je na vrhu stoga (iznad 'vrh_stoga')

	//provjeri je li to u adr. prostoru procesa!
	//(za napraviti)

	*kontekst = *kopija; //obnavlja kontekst sa stoga dretve
	//time ce se azurirati i kazaljka stoga
}

void arh_ispisi_kontekst (void *_kontekst)
{
	kontekst_dretve_t *k = _kontekst;

	j_ispisi("segm:\t%x %x %x %x\n", (uint32) k->gs, (uint32) k->fs, 
		(uint32) k->es, (uint32) k->ds);

	j_ispisi("kodgr:\t%d\n", k->kod_greske);

	j_ispisi("eip:\t%x\n", k->eip);

	j_ispisi("cs:\t%x\n", k->cs);

	j_ispisi("eflags:\t%x\n", k->eflags);

	j_ispisi("esp:\t%x\n", k->esp);

	j_ispisi("ss:\t%x\n", k->ss);
}

/*

http://www.angelcode.com/dev/callconv/callconv.html
http://en.wikipedia.org/wiki/X86_calling_conventions

*/